<?php
require(dirname(__FILE__) . "/class.tqq_action.php");

class cmsdream_tqq {
	private static $_app_key = '801061030';
	private static $_app_secret = '902ac06d30eb15ab6d72ddf72d4675c9';
	private static $_oauth_token = 'e21680e727aa42e5846f99a08f44c772';
	private static $_oauth_token_secret = '38e765aa4ea3a09f64f58b5f05407f3c';
	
	public static $_OAUTH_VERSION = '1.0';
	public static $_OAUTH_RETURN_FORMAT = 'json';
	public static $_OAUTH_OPEN_HOST = 'http://open.t.qq.com';
	
	private static $apiClient;
	
	
	public static function api() {
		if(isset(self::$apiClient)) {
			return self::$apiClient;
		}
		
		self::$apiClient = new cmsdream_tqq_action(self::$_app_key, self::$_app_secret, self::$_oauth_token, self::$_oauth_token_secret);
		return self::$apiClient;
	}
	
	public function __construct() {
		
	}
	
	public function __destruct(){
	
	}
	
}

class cmsdream_tqq_open_request {
	
	function __construct($consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL){
		$this->sha1_method = new cmsdream_tqq_oauth_signature_method_hmac_sha1();
		$this->consumer = new cmsdream_tqq_oauth($consumer_key, $consumer_secret);
		if(! empty($oauth_token) && ! empty($oauth_token_secret)){
			$this->token = new cmsdream_tqq_oauth($oauth_token, $oauth_token_secret);
		} else {
			$this->token = NULL;
		}
	}

	public function get($url, $parameters) {
		$rst = $this->oAuthRequest($url, 'GET', $parameters);
		return $this->jsonDecode($rst);
	}
    
	public function post($url, $parameters = array(), $multi = false)  {
		$rst = $this->oAuthRequest($url, 'POST', $parameters, $multi);
		return $this->jsonDecode($rst);
	}
	
	private function jsonDecode($rst, $assoc = true) {
		$rst = preg_replace('/[^\x20-\xff]*/', '', $rst);
		return json_decode($rst, $assoc);
	}

	private function oAuthRequest($url, $method, $parameters, $multi = false) {        
		$request = cmsdream_tqq_oauth_request::from_consumer_and_token($this->consumer,$method, $this->token, $url, $parameters);
		$request->sign_request($this->sha1_method, $this->consumer, $this->token);
		switch($method) {
			case 'GET':
				return $this->http($request->to_url(), 'GET');
			default:
				return $this->http($request->get_normalized_http_url(), $method, $request->to_postdata($multi), $multi);
		}
	}

	public function http($url, $method, $postfields = NULL, $multi = false) {
		$tmp = '<hr>' . $url . '<hr>' . $method . '<hr>' . $postfields . '<hr>';
		$parts = parse_url($url);
		
		$scheme = $parts['scheme'];
		$host = $parts['host'];
		$port = 80;
		
		if($scheme == 'https') {
			$port = 443;
			$version = '1.1';
			$host = 'ssl://' . $host;
		} else {
			
			$version = '1.0';
		}
		$header = "$method $url HTTP/$version\r\n";
		$header .= "Host: $host\r\n";
		if($multi) {
			$header .= "Content-Type: multipart/form-data; boundary=" . cmsdream_tqq_oauth_util::$boundary . "\r\n";
		} else {
			$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
		}
		if(strtolower($method) == 'post') {
			$header .= "Content-Length: " . strlen($postfields) . "\r\n";
			$header .= "Connection: Close\r\n\r\n";
			$header .= $postfields;
		} else {
			$header .= "Connection: Close\r\n\r\n";
		}

		$ret = '';
		$fp = fsockopen($host, $port, $errno, $errstr, 10);

		if(! $fp) {
			throw new Exception('creating connection error.');
		} else {
			fwrite($fp, $header);
			while(! feof($fp)) {
				$ret .= fgets($fp, 4096);
			}
			fclose($fp);
			//$response=split("\r\n\r\n",$ret);
			if(strrpos($ret, 'Transfer-Encoding: chunked')) {
				$info = explode("\r\n\r\n", $ret);
				$response = explode("\r\n", $info[1]);
				$t = array_slice($response, 1, - 1);

				$returnInfo = implode('', $t);
			} else {
				$response = explode("\r\n\r\n", $ret);
				$returnInfo = $response[1];
			}
			return iconv("utf-8", "utf-8//ignore", $returnInfo);
		}
	}
	
}

class cmsdream_tqq_oauth_request {
	private $method = 'POST';
	
	public function __construct($http_url, $method, $parameters = NULL) {
		@$parameters or $parameters = array();
		$this->http_url = $http_url;
		$this->method = $method;
		$this->parameters = $parameters;
	}
	
	public static function from_consumer_and_token($consumer, $method, $token, $http_url, $parameters = NULL) {
		@$parameters or $parameters = array();
		$defaults = array(	"oauth_version" => cmsdream_tqq::$_OAUTH_VERSION, 
							"oauth_nonce" => self::generate_nonce(), 
							"oauth_timestamp" => self::generate_timestamp(),
							"oauth_consumer_key" => $consumer->key
						);
		if($token) $defaults['oauth_token'] = $token->key;
		
		$parameters = array_merge($defaults, $parameters);
		return new self($http_url, $method, $parameters);
	}
	
	public function sign_request($signature_method, $consumer, $token) {
		$this->set_parameter("oauth_signature_method", $signature_method->get_name(), false);
		$signature = $this->build_signature($signature_method, $consumer, $token);
		$this->set_parameter("oauth_signature", $signature, false);
	}

	public function set_parameter($name, $value, $allow_duplicates = true) {
		if($allow_duplicates && isset($this->parameters[$name])) {
			if(is_scalar($this->parameters[$name])) {
				$this->parameters[$name] = array($this->parameters[$name]);
			}			
			$this->parameters[$name][] = $value;
		} else {
			$this->parameters[$name] = $value;
		}
	}
	
	public function get_signature_base_string() {
		$parts = array($this->get_normalized_http_method(), $this->get_normalized_http_url(), 
		$this->get_signable_parameters());
		
		$parts = cmsdream_tqq_oauth_util::urlencode_rfc3986($parts);
		return implode('&', $parts);
	}
	
	public function get_signable_parameters() {
		$params = $this->parameters;
		
		// remove pic 
		if(isset($params['pic'])) {
			unset($params['pic']);
		}
		
		if(isset($params['image'])) {
			unset($params['image']);
		}
		
		// Remove oauth_signature if present 
		// Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.") 
		if(isset($params['oauth_signature'])) {
			unset($params['oauth_signature']);
		}
		
		return cmsdream_tqq_oauth_util::build_http_query($params);
	}
	
	public function get_normalized_http_method() {
		return strtoupper($this->method);
	}

	public function to_url() {
		$post_data = $this->to_postdata();
		$out = $this->get_normalized_http_url();
		if($post_data)  {
			$out .= '?' . $post_data;
		}
		return $out;
	}

	public function get_normalized_http_url() {
		$parts = parse_url($this->http_url);
		
		$port = @$parts['port'];
		$scheme = $parts['scheme'];
		$host = $parts['host'];
		$path = @$parts['path'];
		
		$port or $port = ($scheme == 'https') ? '443' : '80';
		
		if(($scheme == 'https' && $port != '443') || ($scheme == 'http' && $port != '80')) {
			$host = "$host:$port";
		}
		return "$scheme://$host$path";
	}
	
	public function to_postdata($multi = false) {
		if($multi)
			return cmsdream_tqq_oauth_util::build_http_query_multi($this->parameters);
		else
			return cmsdream_tqq_oauth_util::build_http_query($this->parameters);
	}

	public function build_signature($signature_method, $consumer, $token) {
		$signature = $signature_method->build_signature($this, $consumer, $token);
		return $signature;
	}

	public static function generate_timestamp() {
		return time();
	}
	
	public static function generate_nonce() {
		$mt = microtime();
		$rand = mt_rand();
		return md5($mt . $rand);
	}
}

class cmsdream_tqq_oauth {
	public $key;
	public $secret;

	function __construct($key, $secret) {
		$this->key = $key;
		$this->secret = $secret;
	}

	function __toString() {
		return "Open_OAuth[key=$this->key,secret=$this->secret]";
	}
}

class cmsdream_tqq_oauth_signature_method {
	public function check_signature(&$request, $consumer, $token, $signature) {
		$built = $this->build_signature($request, $consumer, $token);
		return $built == $signature;
	}
}

class cmsdream_tqq_oauth_signature_method_hmac_sha1 extends cmsdream_tqq_oauth_signature_method {
	function get_name() {
		return "HMAC-SHA1";
	}

	public function build_signature($request, $consumer, $token) {
		$base_string = $request->get_signature_base_string();
		//echo $base_string."<hr>";
		$request->base_string = $base_string;		
		//echo "<hr/>";
		$key_parts = array($consumer->secret, ($token) ? $token->secret : "");		
		$key_parts = cmsdream_tqq_oauth_util::urlencode_rfc3986($key_parts);		
		$key = implode('&', $key_parts);
		//echo "<hr/>";
		return base64_encode(hash_hmac('sha1', $base_string, $key, true));
	}
}

class cmsdream_tqq_oauth_util {
	public static $boundary = '';

	public static function urlencode_rfc3986($input) {
		if(is_array($input)) {
			return array_map(array('cmsdream_tqq_oauth_util', 'urlencode_rfc3986'), $input);
		} else if(is_scalar($input)) {
			return str_replace('+', ' ', str_replace('%7E', '~', rawurlencode($input)));
		} else {
			return '';
		}
	}
	

	public static function build_http_query($params) {
		if(! $params) return '';
		
		$keys = self::urlencode_rfc3986(array_keys($params));
		$values = self::urlencode_rfc3986(array_values($params));
		$params = array_combine($keys, $values);
		uksort($params, 'strcmp');
		
		$pairs = array();
		foreach($params as $parameter => $value) {
			if(is_array($value)) {
				natsort($value);
				foreach($value as $duplicate_value) {
					$pairs[] = $parameter . '=' . $duplicate_value;
				}
			} else {
				$pairs[] = $parameter . '=' . $value;
			}
		}
		return implode('&', $pairs);
	}
	
	public static function build_http_query_multi($params) {
		if(!$params) return '';
		
		// Urlencode both keys and values 
		$keys = array_keys($params);
		$values = array_values($params);
		$params = array_combine($keys, $values);
		
		// Parameters are sorted by name, using lexicographical byte value ordering. 
		// Ref: Spec: 9.1.1 (1) 
		uksort($params, 'strcmp');
		
		$pairs = array();
		
		self::$boundary = $boundary = uniqid('------------------');
		$MPboundary = '--' . $boundary;
		$endMPboundary = $MPboundary . '--';
		$multipartbody = '';
		
		foreach($params as $parameter => $value) {
			//if( $parameter == 'pic' && $value{0} == '@' )
			if(in_array($parameter, array("pic", "image"))) {
				/*
				$tmp = 'E:\iweibo_proj\trunk\1.txt';
				$url = ltrim($tmp,'@');
				$content = file_get_contents( $url );
				$filename = reset( explode( '?' , basename( $url ) ));
				$mime = self::get_image_mime($url); 
				*/
				//$url = ltrim( $value , '@' );
				$content = $value[2]; //file_get_contents( $url );
				$filename = $value[1]; //reset( explode( '?' , basename( $url ) ));
				$mime = $value[0]; //self::get_image_mime($url); 
				

				$multipartbody .= $MPboundary . "\r\n";
				$multipartbody .= 'Content-Disposition: form-data; name="' . $parameter . '"; filename="' . $filename .
				 '"' . "\r\n";
				$multipartbody .= 'Content-Type: ' . $mime . "\r\n\r\n";
				$multipartbody .= $content . "\r\n";
			} else {
				$multipartbody .= $MPboundary . "\r\n";
				$multipartbody .= 'Content-Disposition: form-data; name="' . $parameter . "\"\r\n\r\n";
				$multipartbody .= $value . "\r\n";
			
			}
		}
		
		$multipartbody .= "$endMPboundary\r\n";
		// For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61) 
		// Each name-value pair is separated by an '&' character (ASCII code 38) 
		// echo $multipartbody;
		return $multipartbody;
	}
	
}



